<template>
	<view class="gesture-password-container" :style="{width: size + 'rpx', height: size + 'rpx', backgroundColor: backgroundColor}">
		<canvas canvas-id="gesture-password" class="gesture-canvas" :style="{width: size + 'rpx', height: size + 'rpx'}" 
			@touchstart="onTouchStart" @touchmove="onTouchMove" @touchend="onTouchEnd"
			@mousedown="onMouseDown" @mousemove="onMouseMove" @mouseup="onMouseUp"></canvas>
	</view>
</template>

<script>
	export default {
		name: 'gesture-password',
		props: {
			// 容器大小
			size: {
				type: Number,
				default: 600
			},
			// 圆点半径
			cycleRadius: {
				type: Number,
				default: 10
			},
			// 背景色
			backgroundColor: {
				type: String,
				default: 'transparent'
			},
			// 正常状态颜色
			normalColor: {
				type: String,
				default: '#FFFFFF'
			},
			// 选中状态颜色
			selectColor: {
				type: String,
				default: '#F3C822'
			},
			// 错误状态颜色
			errorColor: {
				type: String,
				default: '#FF0000'
			},
			// 最小连接点数
			minPointNum: {
				type: Number,
				default: 4
			},
			// 已设置的密码，用于验证
			password: {
				type: String,
				default: ''
			}
		},
		data() {
			return {
				ctx: null, // canvas上下文
				points: [], // 9个圆点
				selectPoints: [], // 已选择的点
				currentPoint: null, // 当前手指位置
				offsetX: 0, // canvas的X偏移
				offsetY: 0, // canvas的Y偏移
				isMoving: false, // 是否正在移动
				isError: false, // 是否出错
				rpxRatio: 1, // rpx与px的比例
				isInitialized: false // 是否已初始化
			}
		},
		mounted() {
			this.initCanvas();
		},
		methods: {
			// 初始化canvas
			initCanvas() {
				console.log('初始化Canvas开始');
				
				// 重新获取canvas元素
				const query = uni.createSelectorQuery().in(this);
				query.select('.gesture-canvas').boundingClientRect(data => {
					if (!data) {
						console.log('未找到Canvas元素，延迟重试');
						// 如果获取不到元素，延迟重试
						setTimeout(() => {
							this.initCanvas();
						}, 300);
						return;
					}
					
					console.log('Canvas元素信息:', data);
					
					// 计算rpx与px的比例
					this.rpxRatio = data.width / this.size;
					
					// 计算canvas的偏移
					this.offsetX = data.left;
					this.offsetY = data.top;
					
					console.log('Canvas计算参数:', {
						rpxRatio: this.rpxRatio,
						offsetX: this.offsetX,
						offsetY: this.offsetY,
						size: this.size
					});
					
					// 初始化canvas上下文
					this.ctx = uni.createCanvasContext('gesture-password', this);
					
					// 初始化9个点
					this.initPoints();
					
					// 绘制初始状态
					this.draw();
					
					this.isInitialized = true;
					console.log('Canvas初始化完成');
				}).exec();
			},
			
			// 初始化9个点的位置
			initPoints() {
				this.points = [];
				const pointSize = this.size / 6; // 点之间的距离
				const startX = pointSize;
				const startY = pointSize;
				
				for (let i = 0; i < 3; i++) {
					for (let j = 0; j < 3; j++) {
						const x = startX + j * 2 * pointSize;
						const y = startY + i * 2 * pointSize;
						this.points.push({
							x,
							y,
							index: i * 3 + j,
							isSelect: false
						});
					}
				}
			},
			
			// 绘制
			draw() {
				if (!this.ctx) return;
				
				this.ctx.clearRect(0, 0, this.size, this.size);
				
				// 绘制所有点
				this.points.forEach(point => {
					this.drawPoint(point);
				});
				
				// 绘制已选择点之间的连线
				if (this.selectPoints.length > 0) {
					this.drawLines();
				}
				
				this.ctx.draw();
			},
			
			// 绘制单个点
			drawPoint(point) {
				this.ctx.beginPath();
				this.ctx.arc(point.x, point.y, this.cycleRadius, 0, Math.PI * 2, true);
				
				if (point.isSelect) {
					// 选中状态
					this.ctx.setFillStyle(this.isError ? this.errorColor : this.selectColor);
				} else {
					// 正常状态
					this.ctx.setFillStyle(this.normalColor);
				}
				
				this.ctx.fill();
				
				// 绘制内圆
				if (point.isSelect) {
					this.ctx.beginPath();
					this.ctx.arc(point.x, point.y, this.cycleRadius / 2, 0, Math.PI * 2, true);
					this.ctx.setFillStyle(this.isError ? this.errorColor : this.selectColor);
					this.ctx.fill();
				}
			},
			
			// 绘制连线
			drawLines() {
				this.ctx.beginPath();
				this.ctx.setLineWidth(3);
				this.ctx.setStrokeStyle(this.isError ? this.errorColor : this.selectColor);
				
				// 连接已选择的点
				for (let i = 0; i < this.selectPoints.length; i++) {
					const point = this.selectPoints[i];
					if (i === 0) {
						this.ctx.moveTo(point.x, point.y);
					} else {
						this.ctx.lineTo(point.x, point.y);
					}
				}
				
				// 连接到当前手指位置
				if (this.currentPoint && this.isMoving) {
					this.ctx.lineTo(this.currentPoint.x, this.currentPoint.y);
				}
				
				this.ctx.stroke();
			},
			
			// 检测点是否被触摸
			checkTouchPoint(x, y) {
				for (let i = 0; i < this.points.length; i++) {
					const point = this.points[i];
					const distance = Math.sqrt(Math.pow(point.x - x, 2) + Math.pow(point.y - y, 2));
					
					if (distance < this.cycleRadius && !point.isSelect) {
						return point;
					}
				}
				return null;
			},
			
			// 处理坐标转换
			handleCoordinates(clientX, clientY) {
				// 获取当前页面的滚动位置
				let scrollLeft = 0;
				let scrollTop = 0;
				
				try {
					// 在不同平台获取滚动位置
					// #ifdef H5
					scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
					scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
					// #endif
				} catch (e) {
					console.error('获取滚动位置失败:', e);
				}
				
				// 计算相对于canvas的坐标
				const x = (clientX - this.offsetX + scrollLeft) / this.rpxRatio;
				const y = (clientY - this.offsetY + scrollTop) / this.rpxRatio;
				
				console.log('触摸坐标:', {
					clientX, clientY,
					offsetX: this.offsetX,
					offsetY: this.offsetY,
					rpxRatio: this.rpxRatio,
					x, y
				});
				
				return { x, y };
			},
			
			// 触摸开始
			onTouchStart(e) {
				console.log('触摸开始:', e);
				
				if (!this.isInitialized) {
					console.log('组件未初始化，重新初始化');
					this.initCanvas();
					return;
				}
				
				// 重置状态
				this.selectPoints = [];
				this.isError = false;
				this.isMoving = true;
				
				// 更新所有点的状态
				this.points.forEach(point => {
					point.isSelect = false;
				});
				
				// 获取触摸点位置
				const touch = e.touches[0] || e.changedTouches[0];
				if (!touch) {
					console.error('无法获取触摸点信息');
					return;
				}
				
				// 重新获取canvas位置
				const query = uni.createSelectorQuery().in(this);
				query.select('.gesture-canvas').boundingClientRect(data => {
					if (!data) {
						console.error('无法获取Canvas位置');
						return;
					}
					
					// 更新canvas偏移
					this.offsetX = data.left;
					this.offsetY = data.top;
					
					const coords = this.handleCoordinates(touch.clientX, touch.clientY);
					
					// 检测是否触摸到点
					const point = this.checkTouchPoint(coords.x, coords.y);
					if (point) {
						point.isSelect = true;
						this.selectPoints.push(point);
					}
					
					// 更新当前手指位置
					this.currentPoint = coords;
					
					// 重绘
					this.draw();
				}).exec();
			},
			
			// 触摸移动
			onTouchMove(e) {
				if (!this.isMoving || !this.isInitialized) return;
				
				// 获取触摸点位置
				const touch = e.touches[0] || e.changedTouches[0];
				if (!touch) {
					console.error('无法获取触摸点信息');
					return;
				}
				
				e.preventDefault && e.preventDefault(); // 阻止默认行为
				e.stopPropagation && e.stopPropagation(); // 阻止事件冒泡
				
				const coords = this.handleCoordinates(touch.clientX, touch.clientY);
				
				// 更新当前手指位置
				this.currentPoint = coords;
				
				// 检测是否触摸到新的点
				const point = this.checkTouchPoint(coords.x, coords.y);
				if (point) {
					// 检查是否已经选择过该点
					const existingPoint = this.selectPoints.find(p => p.index === point.index);
					if (!existingPoint) {
						point.isSelect = true;
						this.selectPoints.push(point);
					}
				}
				
				// 重绘
				this.draw();
			},
			
			// 触摸结束
			onTouchEnd(e) {
				if (!this.isInitialized) return;
				
				console.log('触摸结束:', e);
				
				this.isMoving = false;
				this.currentPoint = null;
				
				// 获取密码
				const password = this.selectPoints.map(p => p.index).join('');
				console.log('生成的密码:', password);
				
				// 判断密码是否符合要求
				if (this.selectPoints.length < this.minPointNum) {
					console.log('密码点数不足:', this.selectPoints.length);
					this.isError = true;
					this.draw();
					
					setTimeout(() => {
						// 重置状态
						this.selectPoints = [];
						this.isError = false;
						this.points.forEach(point => {
							point.isSelect = false;
						});
						this.draw();
					}, 1000);
					
					this.$emit('end', '', false, '至少连接' + this.minPointNum + '个点');
					return;
				}
				
				// 如果有密码，进行验证
				if (this.password && this.password !== password) {
					console.log('密码不匹配:', {
						输入: password,
						预设: this.password
					});
					this.isError = true;
					this.draw();
					
					setTimeout(() => {
						// 重置状态
						this.selectPoints = [];
						this.isError = false;
						this.points.forEach(point => {
							point.isSelect = false;
						});
						this.draw();
					}, 1000);
					
					this.$emit('end', password, false, '手势密码错误');
					return;
				}
				
				// 重绘
				this.draw();
				
				// 触发结束事件
				console.log('密码验证成功');
				this.$emit('end', password, true, '');
			},
			
			// 鼠标按下 (适用于H5)
			onMouseDown(e) {
				// #ifdef H5
				this.onTouchStart({
					touches: [{ clientX: e.clientX, clientY: e.clientY }]
				});
				// #endif
			},
			
			// 鼠标移动 (适用于H5)
			onMouseMove(e) {
				// #ifdef H5
				if (this.isMoving) {
					this.onTouchMove({
						touches: [{ clientX: e.clientX, clientY: e.clientY }]
					});
				}
				// #endif
			},
			
			// 鼠标释放 (适用于H5)
			onMouseUp() {
				// #ifdef H5
				this.onTouchEnd();
				// #endif
			},
			
			// 重置
			reset() {
				this.selectPoints = [];
				this.isError = false;
				this.isMoving = false;
				this.currentPoint = null;
				
				this.points.forEach(point => {
					point.isSelect = false;
				});
				
				this.draw();
			}
		}
	}
</script>

<style>
	.gesture-password-container {
		position: relative;
		margin: 0 auto;
		touch-action: none; /* 防止触摸事件被浏览器处理 */
		background-color: white;
	}
	
	.gesture-canvas {
		position: absolute;
		top: 0;
		left: 0;
		touch-action: none; /* 防止触摸事件被浏览器处理 */
	}
</style> 